#pragma once
#include "tcpServer.hpp"
#include <sys/epoll.h>
#define NUM 20
#define SIZE 64
#define DFL -1

class Backage
{
    public:
    Backage(int fd , int pos = 0)
      :_fd(fd)
      ,_pos(pos)
      {
          memset(_buf,0,sizeof(_buf));
      }
      int _fd;/*nullptr方便判定是否为lsock监听套接字*/
      int _pos;
      char _buf[20];
    ~Backage() = default;
};

class EpollServer
{
    public:
      EpollServer(int port= 8080)
        :_port(port)
      {

      }
      void EpollServerInit()
      {
        try{
             _lsock = TcpServer::Socket();
             TcpServer::SetSockAddr(_lsock);
             TcpServer::Bind(_lsock,_port);
             TcpServer::Listen(_lsock);
             cout<<"_lsock"<<_lsock<<endl;
             //
             _epollfd = epoll_create(256);//创建epoll模型,创建就绪队列,建立回调机制
             cout<<"epollfd is "<<_epollfd<<endl;
        }  
        catch(exception& e)
        {
            cout<<"EpollServerInit"<<" "<<e.what()<<endl;
        }
      }
      void AddtoEpoll(int sock,uint32_t events)
      {
           struct epoll_event ev;
           ev.events = events;
           if(sock ==_lsock )
           {
               ev.data.ptr =nullptr;
           }
           else{
               ev.data.ptr =(void*) new Backage(sock);
           }
           int res = epoll_ctl(_epollfd,EPOLL_CTL_ADD,sock,&ev);
           if( res < 0 )
           {
              throw runtime_error(string("AddtoEpoll error.."));
           }
      }
      void DelFromEpoll(int sock)/*关闭套接字并从epoll模型中删除*/
      {
          close(sock);
          epoll_ctl(_epollfd,EPOLL_CTL_DEL,sock,nullptr);
      }
      void EpollServerStart()
      {
        AddtoEpoll(_lsock,EPOLLIN);      
        cout<<"listen sock add ok"<<endl;
        struct epoll_event revs[SIZE] ;//就绪队列
        int timeout = -1;
        while(1)
        {
            cout<<"epoll_wait begin"<<endl;
            //cout<< "res="<<res<<endl;
            int res =  epoll_wait( _epollfd, revs, SIZE, timeout);        
            switch(res)
            {
              case 0:
                 cout<<"epoll_wait timeout..."<<endl; 
                 break;
              case -1:
                 cout<<"epoll_wait error..."<<endl;
                 break;
              default:  
                try{
                  cout<<"recvive.."<<endl;
                  Rervice( revs, res );
                }  
                catch(exception& e)
                {
                   cout<<e.what()<<endl;
                }
                break;
            }
        }
      }
      void Rervice(struct epoll_event* readyque,int maxnum)
      {
            for(int i = 0 ; i < maxnum ; i++)
            {
                uint32_t ev = readyque[i].events;
                if( ev & EPOLLIN)
                {
                    cout<< "EPOLLIN" <<endl;
                    if( readyque[i].data.ptr == nullptr)
                    {
                        cout<<"if()"<<endl;
                        int sock = TcpServer::Accept(_lsock); 
                        cout<<"get a new sock:"<<sock<<endl;
                        if( sock > 0 ) AddtoEpoll(sock,EPOLLIN);
                        cout<<"get a new link... sock  "<<sock<<endl;
                    }
                    else{
                        cout<<"else()"<<endl;
                        Backage* bag = (Backage*)readyque[i].data.ptr;
                        ssize_t s = recv( bag->_fd , bag->_buf + bag->_pos , static_cast<int>(sizeof(bag->_buf)) - bag->_pos -1 ,0 );

                        if( s < 0)
                        {
                          throw runtime_error(string("recv < 0 error..."));
                        }
                        if( s == 0 ){
                          DelFromEpoll(bag->_fd); 
                          delete bag;
                          continue;
                        }

                        bag->_pos += s;
                        cout<<"bag->_pos="<<bag->_pos<<endl;
                        cout<<"has recevied : "<<bag->_buf<<endl;
                        if( bag -> _pos >= static_cast<int>(sizeof(bag->_buf))-1 )/*说明读满了,最后一个给'\0'*/
                        {
                           bag->_buf[bag->_pos] = '\0';//memset保证都是'0'
                           cout<<"received#: "<<bag->_buf<<endl;
                           /*修改成等待写事件*/
                           struct epoll_event temp;
                           temp.events = EPOLLOUT;
                           temp.data.ptr = bag;
                           int res = epoll_ctl(_epollfd, EPOLL_CTL_MOD, bag->_fd , &temp);/*转换到写端*/
                           if( res < 0 ){
                             throw runtime_error(string("epoll_crl error.."));
                           }
                           bag->_pos = sizeof(bag->_buf);//算上最后一个
                        }
                    } 
                }
                else if( ev & EPOLLOUT)
                {
                  Backage* bag = (Backage*) readyque[i].data.ptr;
                  ssize_t s= send(bag->_fd,bag->_buf +( static_cast<int>(sizeof(bag->_buf)) - bag->_pos) , bag->_pos , 0);
                  bag->_pos -= s;
                  if( bag ->_pos <= 0 )
                  {
                      DelFromEpoll(bag->_fd);
                      delete(bag);
                  }
                 //  size_t s = send( bag->_fd , bag + bag->_pos , sizeof(bag->_buf) - bag->_pos, 0) ;
                 // bag->_pos -= s;
                 //  if(bag->_pos == 0)
                 //  {
                 //      DelFromEpoll(bag->_fd);/*打印完毕了*/
                 //      delete bag;
                 //  }
                }
            }

      }
      ~EpollServer()
      {
        close(_lsock);
        close(_epollfd);
      }
    private:
      int _lsock;
      int _epollfd;
      int _port;
};
